<!DOCTYPE html>
<html>

<head>
    <title>智能视频处理工具</title>
    <style>
        /* 基础样式 */
        body {
            font-family: 'Segoe UI', sans-serif;
            max-width: 800px;
            margin: 20px auto;
            padding: 20px;
            background-color: #f5f7fa;
        }

        /* 输入区域样式 */
        .control-panel {
            background: white;
            padding: 20px;
            border-radius: 12px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            margin-bottom: 20px;
        }

        .input-group {
            margin: 15px 0;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        label {
            color: #2d3748;
            font-weight: 500;
        }

        input[type="number"] {
            padding: 8px 12px;
            border: 2px solid #e2e8f0;
            border-radius: 6px;
            width: 100px;
        }

        /* 按钮样式 */
        button {
            background: #4299e1;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 6px;
            cursor: pointer;
            transition: background 0.3s ease;
        }

        button:hover {
            background: #3182ce;
        }

        /* 视频容器 */
        .video-container {
            background: white;
            padding: 15px;
            border-radius: 12px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            margin-bottom: 20px;
        }

        /* 进度条样式 */
        progress {
            width: 100%;
            height: 12px;
            border-radius: 6px;
        }

        progress::-webkit-progress-value {
            background: #4299e1;
            border-radius: 6px;
        }

        /* 时间显示 */
        #timeDisplay {
            color: #4a5568;
            font-size: 0.9em;
            margin: 10px 0;
        }

        /* 新增截图参数区域样式 */
        .crop-controls {
            background: #fff;
            padding: 15px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            margin: 15px 0;
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 10px;
        }

        .dimension-info {
            color: #4a5568;
            font-size: 0.9em;
            margin: 10px 0;
        }

        /* 输入框样式优化（网页6、8） */
        .crop-input {
            width: 100%;
            padding: 8px;
            border: 2px solid #e2e8f0;
            border-radius: 6px;
            box-sizing: border-box;
        }
    </style>
</head>

<body>
    <!-- 视频尺寸显示 -->
    <div class="dimension-info" id="videoDimensions">视频尺寸: 加载中...</div>


    <!-- 新增截图参数输入 -->
    <div class="crop-controls">
        <div>
            <label>Left:</label>
            <input type="number" id="cropLeft" class="crop-input" value="0" min="0" step="1">
        </div>
        <div>
            <label>Top:</label>
            <input type="number" id="cropTop" class="crop-input" value="0" min="0" step="1">
        </div>
        <div>
            <label>Width:</label>
            <input type="number" id="cropWidth" class="crop-input" value="0" min="1" step="1">
        </div>
        <div>
            <label>Height:</label>
            <input type="number" id="cropHeight" class="crop-input" value="0" min="1" step="1">
        </div>
    </div>

    <div class="control-panel">
        <div class="input-group">
            <label>截图间隔（帧）：</label>
            <input type="number" id="frameInterval" value="1" min="1" step="1">
        </div>
        <input type="file" id="videoInput" accept="video/*">
        <input type="color" id="colorPicker" value="#00ff00">
        <button onclick="startProcessing()">开始处理</button>
    </div>

    <div class="video-container">
        <video id="sourceVideo" controls style="width: 100%; max-width: 600px;"></video>
    </div>

    <progress id="progress" value="0" max="100"></progress>
    <div id="timeDisplay">当前帧时间: 0s</div>

    <script>
        const video = document.getElementById('sourceVideo');
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d', { willReadFrequently: true });
        let frames = [];
        let targetColor = [0, 255, 0];
        let isProcessing = false;
        let frameCounter = 0;  // 新增帧计数器
        const videoInput = document.getElementById('videoInput');

        // 文件选择监听
        videoInput.addEventListener('change', function (e) {
            const file = e.target.files[0];
            if (!file) return;

            // 创建临时视频对象获取元数据[4](@ref)
            const tempVideo = document.createElement('video');
            tempVideo.src = URL.createObjectURL(file);

            tempVideo.onloadedmetadata = () => {
                // 更新显示参数
                document.getElementById('videoDimensions').textContent =
                    `视频尺寸: ${tempVideo.videoWidth}x${tempVideo.videoHeight}px`;

                // 设置默认值（无需点击操作）[1,2](@ref)
                document.getElementById('cropWidth').value = tempVideo.videoWidth;
                document.getElementById('cropHeight').value = tempVideo.videoHeight;

                URL.revokeObjectURL(tempVideo.src);
            };
        });

        // 获取间隔设置
        function getFrameInterval() {
            const interval = parseInt(document.getElementById('frameInterval').value) || 1;
            return Math.max(1, interval);  // 确保最小值1
        }

        // 初始化颜色选择器
        document.getElementById('colorPicker').addEventListener('input', (e) => {
            const hex = e.target.value.replace('#', '');
            targetColor = [
                parseInt(hex.substr(0, 2), 16),
                parseInt(hex.substr(2, 2), 16),
                parseInt(hex.substr(4, 2), 16)
            ];
        });

        // 主处理函数
        async function startProcessing() {
            const file = document.getElementById('videoInput').files[0];
            if (!file) return alert('请先选择视频文件');

            video.src = URL.createObjectURL(file);
            await new Promise(resolve => {
                video.onloadedmetadata = resolve;
                video.onerror = () => alert("视频加载失败");
            });

            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;

            // 初始化时间轴
            video.currentTime = 0;
            isProcessing = true;
            processVideoFrames();
        }

        // 修改后的处理循环
        async function processVideoFrames() {
            const frameDuration = 1 / 30;
            const interval = getFrameInterval();

            while (isProcessing && video.currentTime < video.duration) {
                frameCounter++;
                if (frameCounter % interval !== 0) {
                    video.currentTime = Math.min(video.currentTime + frameDuration, video.duration);
                    continue;
                }

                await new Promise(resolve => {
                    video.onseeked = () => {
                        processFrame().then(resolve);
                        updateTimeDisplay();
                    };
                    video.currentTime = Math.min(video.currentTime + frameDuration, video.duration);
                });

                if (frames.length % 50 === 0) {
                    await new Promise(r => setTimeout(r, 0));
                }
            }
            exportFrames();
        }

        // 实时更新时间显示
        function updateTimeDisplay() {
            document.getElementById('timeDisplay').textContent =
                `当前帧时间: ${video.currentTime.toFixed(2)}s`;
        }

        // 帧处理函数（优化内存使用）
        async function processFrame() {
            // 获取截图参数并验证
            const cropParams = {
                left: Math.max(0, parseInt(document.getElementById('cropLeft').value)),
                top: Math.max(0, parseInt(document.getElementById('cropTop').value)),
                width: Math.min(video.videoWidth, parseInt(document.getElementById('cropWidth').value)),
                height: Math.min(video.videoHeight, parseInt(document.getElementById('cropHeight').value))
            };

            // 调整画布尺寸（网页6、8）
            canvas.width = cropParams.width;
            canvas.height = cropParams.height;

            // 执行区域截图（网页3、4）
            ctx.drawImage(
                video,
                cropParams.left, cropParams.top,   // 源起点
                cropParams.width, cropParams.height, // 源尺寸
                0, 0,                              // 目标起点
                cropParams.width, cropParams.height  // 目标尺寸
            );
            // ctx.drawImage(video, 0, 0);
            const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imageData.data;
            const [tr, tg, tb] = targetColor;

            // 优化颜色匹配算法[8](@ref)
            for (let i = 0; i < data.length; i += 4) {
                const diff = Math.sqrt(
                    (data[i] - tr) ** 2 + (data[i + 1] - tg) ** 2 + (data[i + 2] - tb) ** 2
                );
                data[i + 3] = diff < 50 ? 0 : 255;
            }

            ctx.putImageData(imageData, 0, 0);
            frames.push(canvas.toDataURL('image/png'));

            // 进度条更新优化[1](@ref)
            const progress = (video.currentTime / video.duration * 100).toFixed(1);
            document.getElementById('progress').value = progress;
        }

        // 导出序列帧为ZIP
        async function exportFrames() {
            isProcessing = false;
            const JSZip = await import('https://cdn.jsdelivr.net/npm/jszip@3.10.1/+esm');
            const zip = new JSZip.default();

            // 分块处理避免内存溢出[7](@ref)
            const chunkSize = 100;
            for (let i = 0; i < frames.length; i += chunkSize) {
                const chunk = frames.slice(i, i + chunkSize);
                chunk.forEach((dataURL, index) => {
                    const base64 = dataURL.split(',')[1];
                    zip.file(`frame_${(i + index).toString().padStart(4, '0')}.png`, base64, { base64: true });
                });
                await new Promise(r => setTimeout(r, 0));
            }

            const blob = await zip.generateAsync({ type: 'blob' });
            const url = URL.createObjectURL(blob);

            const a = document.createElement('a');
            a.href = url;
            a.download = 'frames.zip';
            a.click();

            // 清理资源[4](@ref)
            URL.revokeObjectURL(video.src);
            frames = [];
        }
    </script>
</body>

</html>